 `include "defines.v"

// 译码模块
// 纯组合逻辑电路
module id(

	input wire rst,
    
    // from if_id
    input wire[`InstBus] inst_i,             // 指令内容
    input wire[`InstAddrBus] inst_addr_i,    // 指令地址

    // from regs 
    input wire[`RegBus] reg1_rdata_i,        // 通用寄存器1输入数据 `define RegBus 31:0
    input wire[`RegBus] reg2_rdata_i,        // 通用寄存器2输入数据

    // from ex
    input wire ex_jump_flag_i,               // 跳转标志 跳转时不向总线访问内存
    //from csr reg
    input wire[`RegBus] csr_rdata_i,
    
    //to csr reg
    output reg[`MemAddrBus] csr_raddr_o,     // 读CSR寄存器地址
    // to regs
    output reg[`RegAddrBus] reg1_raddr_o,    // 读通用寄存器1地址
    output reg[`RegAddrBus] reg2_raddr_o,    // 读通用寄存器2地址
    // to ex
    output reg[`InstBus] inst_o,             // 指令内容
    output reg[`InstAddrBus] inst_addr_o,    // 指令地址
    output reg[`RegBus] reg1_rdata_o,        // 通用寄存器1数据
    output reg[`RegBus] reg2_rdata_o,        // 通用寄存器2数据
    output reg reg_we_o,                     // 写通用寄存器标志
    output reg[`RegAddrBus] reg_waddr_o,   // 写通用寄存器地址
    
    output reg csr_we_o,                     // 写CSR寄存器标志
    output reg[`RegBus] csr_rdata_o,         // CSR寄存器数据
    output reg[`MemAddrBus] csr_waddr_o      // 写CSR寄存器地址
    );

    // R类
    wire[6:0] opcode = inst_i[6:0];
    wire[4:0] rd = inst_i[11:7];
    wire[2:0] funct3 = inst_i[14:12];
    wire[4:0] rs1 = inst_i[19:15];
    wire[4:0] rs2 = inst_i[24:20];
    wire[6:0] funct7 = inst_i[31:25];


    always @ (*) begin
        if (rst == `RstEnable) begin
            reg1_raddr_o = `ZeroReg; //`define ZeroReg 5'h0
            reg2_raddr_o = `ZeroReg;

            inst_o = `INST_NOP;
            inst_addr_o = `ZeroWord;

            reg1_rdata_o = `ZeroWord;
            reg2_rdata_o = `ZeroWord;
           
            reg_we_o = `WriteDisable;
            reg_waddr_o = `ZeroReg;
            csr_raddr_o = `ZeroReg;
            csr_waddr_o = `ZeroReg;
            csr_we_o = `WriteDisable;
            csr_rdata_o = `ZeroWord;
        end else begin
            inst_o = inst_i;
            inst_addr_o = inst_addr_i;
            reg1_rdata_o = reg1_rdata_i;
            reg2_rdata_o = reg2_rdata_i;
            csr_rdata_o = csr_rdata_i;
            csr_raddr_o = `ZeroReg;
            csr_waddr_o = `ZeroReg;
            csr_we_o = `WriteDisable;
           

            case (opcode)
                `INST_TYPE_R_M: begin //`define INST_TYPE_R_M 7'b0110011 寄存器-寄存器操作
                    if ((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begin
                        case (funct3)
                            `INST_ADD_SUB, `INST_SLL, `INST_SLT, `INST_SLTU, `INST_XOR, `INST_SR, `INST_OR, `INST_AND: begin
                            //3'b000-2      3'b001      3'b010     3'b011     3'b100     3'b101-2    3'b110   3'b111
                                reg_we_o = `WriteEnable;
                                reg_waddr_o = rd;
                                reg1_raddr_o = rs1;
                                reg2_raddr_o = rs2;
                            end
                            default: begin
                                reg_we_o = `WriteDisable;
                                reg_waddr_o = `ZeroReg;
                                reg1_raddr_o = `ZeroReg;
                                reg2_raddr_o = `ZeroReg;
                            end
                        endcase
                    end else begin
                        reg_we_o = `WriteDisable;
                        reg_waddr_o = `ZeroReg;
                        reg1_raddr_o = `ZeroReg;
                        reg2_raddr_o = `ZeroReg;
                        end
                    end
                `INST_TYPE_L: begin //`define INST_TYPE_L 7'b0000011  Loads
                    case (funct3)
                        `INST_LB, `INST_LH, `INST_LW, `INST_LBU, `INST_LHU: begin   //imm={funct7,rs2}
                            reg1_raddr_o = rs1;
                            reg2_raddr_o = `ZeroReg;
                            reg_we_o = `WriteEnable;
                            reg_waddr_o = rd;
                        end
                        default: begin
                            reg1_raddr_o = `ZeroReg;
                            reg2_raddr_o = `ZeroReg;
                            reg_we_o = `WriteDisable;
                            reg_waddr_o = `ZeroReg;
                        end
                    endcase
                end
                `INST_TYPE_S: begin
                    case (funct3)
                        `INST_SB, `INST_SW, `INST_SH: begin
                            reg1_raddr_o = rs1;
                            reg2_raddr_o = rs2;
                            reg_we_o = `WriteDisable;
                            reg_waddr_o = `ZeroReg;
                        end
                        default: begin
                            reg1_raddr_o = `ZeroReg;
                            reg2_raddr_o = `ZeroReg;
                            reg_we_o = `WriteDisable;
                            reg_waddr_o = `ZeroReg;
                        end
                    endcase
                end
                `INST_TYPE_B:begin
                    case(funct3)
                    `INST_BEQ ,`INST_BNE ,`INST_BLT ,`INST_BGE,`INST_BLTU ,`INST_BGEU: begin
                        reg1_raddr_o = rs1;
                        reg2_raddr_o = rs2;
                        reg_we_o = `WriteDisable;
                        reg_waddr_o = `ZeroReg;
                    end
                    default:begin
                        reg_we_o = `WriteDisable;
                        reg_waddr_o = `ZeroReg;
                        reg1_raddr_o = `ZeroReg;
                        reg2_raddr_o = `ZeroReg;
                    end
                    endcase
                end
                `INST_TYPE_I:begin
                    case(funct3)
                        `INST_ADDI ,`INST_SLTI, `INST_SLTIU ,`INST_XORI,`INST_ORI,`INST_ANDI,`INST_SLLI,`INST_SRI:begin
                            reg_we_o = `WriteEnable;
                            reg_waddr_o = rd;
                            reg1_raddr_o = rs1;
                            reg2_raddr_o = `ZeroReg;
                        end
                        default:begin
                            reg_we_o = `WriteDisable;
                            reg_waddr_o = `ZeroReg;
                            reg1_raddr_o = `ZeroReg;
                            reg2_raddr_o = `ZeroReg;
                        end
                    endcase
                end
                `INST_JAL:begin
                    reg_we_o = `WriteEnable;
                    reg_waddr_o = rd;
                    reg1_raddr_o = `ZeroReg;
                    reg2_raddr_o = `ZeroReg;
                end
                `INST_JALR:begin
                    reg_we_o = `WriteEnable;
                    reg_waddr_o = rd;
                    reg1_raddr_o = rs1;
                    reg2_raddr_o = `ZeroReg;
                end
                `INST_LUI: begin
                    reg_we_o = `WriteEnable;
                    reg_waddr_o = rd;
                    reg1_raddr_o = `ZeroReg;
                    reg2_raddr_o = `ZeroReg;
                end
                `INST_AUIPC: begin
                    reg_we_o = `WriteEnable;
                    reg_waddr_o = rd;
                    reg1_raddr_o = `ZeroReg;
                    reg2_raddr_o = `ZeroReg;
                end
                `INST_CSR: begin
                    reg_we_o = `WriteDisable;
                    reg_waddr_o = `ZeroReg;
                    reg1_raddr_o = `ZeroReg;
                    reg2_raddr_o = `ZeroReg;
                    csr_raddr_o = {20'h0, inst_i[31:20]};
                    csr_waddr_o = {20'h0, inst_i[31:20]};
                    case (funct3)
                        `INST_CSRRW, `INST_CSRRS, `INST_CSRRC: begin
                            reg1_raddr_o = rs1;
                            reg2_raddr_o = `ZeroReg;
                            reg_we_o = `WriteEnable;
                            reg_waddr_o = rd;
                            csr_we_o = `WriteEnable;
                        end
                        `INST_CSRRWI, `INST_CSRRSI, `INST_CSRRCI: begin
                            reg1_raddr_o = `ZeroReg;
                            reg2_raddr_o = `ZeroReg;
                            reg_we_o = `WriteEnable;
                            reg_waddr_o = rd;
                            csr_we_o = `WriteEnable;
                        end
                        default: begin
                            reg_we_o = `WriteDisable;
                            reg_waddr_o = `ZeroReg;
                            reg1_raddr_o = `ZeroReg;
                            reg2_raddr_o = `ZeroReg;
                            csr_we_o = `WriteDisable;
                        end
                    endcase
                end
                default: begin
                    reg_we_o = `WriteDisable;
                    reg_waddr_o = `ZeroReg;
                    reg1_raddr_o = `ZeroReg;
                    reg2_raddr_o = `ZeroReg;
                end
            endcase
        end
    end

endmodule
